/*******************************************************************
*
*    DESCRIPTION:Add,delete or modify ip rules.
*
*    AUTHOR:LiuHui
*
*    HISTORY:
*
*    DATE:1/22/2007
*
*******************************************************************/
/** include files **/
#include <config.h>
#include <debug.h>
#include <header.h>
#include "rules.h"
#include "language.h"
/** local definitions **/

enum ip_conntrack_info
{
	/* Part of an established connection (either direction). */
	IP_CT_ESTABLISHED,

	/* Like NEW, but related to an existing connection, or ICMP error
	   (in either direction). */
	IP_CT_RELATED,

	/* Started a new connection to track (only
           IP_CT_DIR_ORIGINAL); may be a retransmission. */
	IP_CT_NEW,

	/* >= this indicates reply direction */
	IP_CT_IS_REPLY,

	/* Number of distinct IP_CT types (no NEW in reply dirn). */
	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
};

/* default settings */

/** external functions **/

/** external data **/

/** internal functions **/
static void flush_chain(const char *chain_name);
static void delete_user_defined_chain(const char *chain_name);
static void enable_lo_interface(const char *chain_name);
static void add_bypass_rule(const char *chain_name);
static void create_user_defined_chain(const char *chain_name);
static void jump_to_user_defined_chain(const char *main_chain, const char *sub_chain);
static void add_queue_rule(const char *chain_name, int protocol);
static void flush_chain(const char *chain_name);
static void set_default_policy(const char *chain_name, const char *policy);
static void ipt_add_user_defined_rules(int proto,
                                       int lpf_value, int lpt_value,
                                       int rpf_value, int rpt_value,
                                       int action, const char *chain_name);
static void ipt_delete_user_defined_rules(int proto,
                                          int lpf_value, int lpt_value,
                                          int rpf_value, int rpt_value,
                                          int action, char *chain_name);

static struct ipt_entry_match *ipt_generate_match(void *extend_match, 
                                                  const char *extend_match_name,
                                                  int extend_match_size);
static struct ipt_entry *ipt_generate_entry(struct ipt_entry *fw,
                                            struct ipt_entry_match *match,
                                            struct ipt_entry_target *target);
static void ipt_entry_init(struct ipt_entry* entry, struct in_addr s_ip, struct in_addr s_mask,
                           struct in_addr d_ip, struct in_addr d_mask, unsigned short proto,
                           const char *in_iface, const char *out_iface);
static void ipt_standard_target_init(struct ipt_standard_target *target, const char *policy);
static struct ipt_entry_target* ipt_generate_target(void *extend_target,
                                                    int extend_target_size,
                                                    const char *target_name);

static int get_user_defined_rule_num(int proto,
                                     int lpf_value, int lpt_value,
                                     int rpf_value, int rpt_value,
                                     int action, char *chain_name);
static int is_find_rule(struct ipt_entry *e, iptc_handle_t *h,
                        int proto, int spf, int spt,
                        int dpf, int dpt, int action);

/** public data **/

/** private data **/
/** public functions **/
void init_default_rules(void)
{
  /*clean filter table*/
  clean_filter_table();
  /*clear user-defined chain*/
  /*enable lo interface*/
//	enable_lo_interface(INPUT_CHAIN);
//	enable_lo_interface(OUTPUT_CHAIN);
  /*add bypass rules*/
  add_bypass_rule(INPUT_CHAIN);
  add_bypass_rule(OUTPUT_CHAIN);/*flush INPUT and OUTPUT*/
  /*set defaut policy DROP*/

  /*create user-defined chain*/
  create_user_defined_chain(INPUT_USER_DEFINED_CHAIN);
  create_user_defined_chain(OUTPUT_USER_DEFINED_CHAIN);
  /*add jump user-defined rules*/
  jump_to_user_defined_chain(INPUT_CHAIN, INPUT_USER_DEFINED_CHAIN);
  jump_to_user_defined_chain(OUTPUT_CHAIN, OUTPUT_USER_DEFINED_CHAIN);

  /*create misc chain*/
  create_user_defined_chain(INPUT_MISC_CHAIN);
  create_user_defined_chain(OUTPUT_MISC_CHAIN);
  /*add jump misc chain rules*/
  jump_to_user_defined_chain(INPUT_CHAIN, INPUT_MISC_CHAIN);
  jump_to_user_defined_chain(OUTPUT_CHAIN, OUTPUT_MISC_CHAIN);

  /*add queue rules*/
  add_queue_rule(INPUT_CHAIN, IPPROTO_TCP);
  add_queue_rule(INPUT_CHAIN, IPPROTO_UDP);
  add_queue_rule(OUTPUT_CHAIN, IPPROTO_TCP);
  add_queue_rule(OUTPUT_CHAIN, IPPROTO_UDP);
  /*set default policy DROP*/
  set_default_policy(INPUT_CHAIN, "DROP");
  set_default_policy(OUTPUT_CHAIN, "DROP");
}
void clean_filter_table(void)
{
  flush_chain(INPUT_CHAIN);
  flush_chain(OUTPUT_CHAIN);
  flush_chain(INPUT_MISC_CHAIN);
  flush_chain(OUTPUT_MISC_CHAIN);
  flush_chain(INPUT_USER_DEFINED_CHAIN);
  flush_chain(OUTPUT_USER_DEFINED_CHAIN);
  set_default_policy(INPUT_CHAIN, "ACCEPT");
  set_default_policy(OUTPUT_CHAIN, "ACCEPT");
  delete_user_defined_chain(INPUT_MISC_CHAIN);
  delete_user_defined_chain(OUTPUT_MISC_CHAIN);
  delete_user_defined_chain(INPUT_USER_DEFINED_CHAIN);
  delete_user_defined_chain(OUTPUT_USER_DEFINED_CHAIN);
}

void add_user_defined_rules(int proto,
                            int lpf_value, int lpt_value,
                            int rpf_value, int rpt_value,
                            int action)
{
  ipt_add_user_defined_rules(proto, lpf_value, lpt_value,
                             rpf_value, rpt_value, action,
                             INPUT_USER_DEFINED_CHAIN);

  ipt_add_user_defined_rules(proto, lpf_value, lpt_value,
                             rpf_value, rpt_value, action,
                             OUTPUT_USER_DEFINED_CHAIN);
}

void delete_user_defined_rules(int proto,
                               int lpf_value, int lpt_value,
                               int rpf_value, int rpt_value,
                               int action)
{ 
  ipt_delete_user_defined_rules(proto, lpf_value, lpt_value,
                                rpf_value, rpt_value, action,
                                INPUT_USER_DEFINED_CHAIN);

  ipt_delete_user_defined_rules(proto, lpf_value, lpt_value,
                                rpf_value, rpt_value, action,
                                OUTPUT_USER_DEFINED_CHAIN);
}
/** private functions **/
static void flush_chain(const char *chain_name)
{
  iptc_handle_t h = NULL;
  int result = 0;
  h = iptc_init(FILTER_TABLE);

  if (NULL == h)
  {
    __ERROR_MSG("Error when iptc_init:%s\n", iptc_strerror(errno));
    goto out;
  }
  if (!iptc_is_chain(chain_name, h))
  {
    goto out;
  }
  result = iptc_flush_entries(chain_name, &h);
  if (0 == result)
  {
    __ERROR_MSG("Error when iptc_flush_entries %s:%s\n", chain_name, iptc_strerror(errno));
    goto out;
  }

  result = iptc_commit(&h);
  if (0 == result)
  {
    __ERROR_MSG("Error when iptc_commit:%s", iptc_strerror(errno));
    goto out;
  }
  out:
  if (h != NULL)
  {
    iptc_free(&h);
  }
  return;
}
static void delete_user_defined_chain(const char *chain_name){
  iptc_handle_t h = NULL;
  int result = 0;
  h = iptc_init(FILTER_TABLE);
  if (NULL == h)
  {
    __ERROR_MSG("Error when iptc_init:%s\n", iptc_strerror(errno));
    return;
  }
  if (iptc_is_chain(chain_name, h))
  {
    result = iptc_flush_entries(chain_name, &h);
    if (0 == result)
    {
      __ERROR_MSG("Error when iptc_flush_entries:%s\n", iptc_strerror(errno));
      goto out;
    }

    result = iptc_delete_chain(chain_name, &h);
    if (0 == result)
    {
      __ERROR_MSG("Error when iptc_delete_chain:%s\n", iptc_strerror(errno));
      goto out;
    }

    result = iptc_commit(&h);
    if (0 == result)
    {
      __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
      goto out;
    }
  }
  out:
  if (h != NULL)
  {
    iptc_free(&h);
  }
}
static void enable_lo_interface(const char *chain_name)
{
  iptc_handle_t h = NULL;
  struct in_addr param;
  struct ipt_entry lo_entry;
  struct ipt_standard_target lo_target;
  struct ipt_entry *e = NULL;

  if ((h = iptc_init(FILTER_TABLE)) == NULL)
  {
    return;
  }

  param.s_addr = INADDR_ANY;
  if (0 == strcmp(chain_name, INPUT_CHAIN))
  {
    ipt_entry_init(&lo_entry, param, param, param, param, 0, LO_IFACE, NULL);
  }
  else if (0 == strcmp(chain_name, OUTPUT_CHAIN))
  {
    ipt_entry_init(&lo_entry, param, param, param, param, 0, NULL, LO_IFACE);
  }

  ipt_standard_target_init(&lo_target, "ACCEPT");

  e = ipt_generate_entry(&lo_entry, NULL, (struct ipt_entry_target*)&lo_target);

  if (iptc_append_entry(chain_name, e, &h) == 0)
  {
    __ERROR_MSG("Error when append:%s\n", iptc_strerror(errno));
    goto out;
  }

  if (iptc_commit(&h) == 0)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }

  out:
  if (e != NULL)  free(e);
  return;
}

static void add_bypass_rule(const char *chain_name)
{
  iptc_handle_t h = NULL;
  struct in_addr param;
  struct ipt_entry bypass_entry;
  struct ipt_standard_target bypass_target;
  struct ipt_entry_match *m = NULL;
  struct ipt_state_info bypass_state;
  struct ipt_entry *e = NULL;

  if ((h = iptc_init(FILTER_TABLE)) == NULL)
  {
    return;
  }

  param.s_addr = INADDR_ANY;
  ipt_entry_init(&bypass_entry, param, param, param, param, 0, NULL, NULL);

  bypass_state.statemask = 0;
  bypass_state.statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED);
  bypass_state.statemask |= IPT_STATE_BIT(IP_CT_RELATED);
  m = ipt_generate_match(&bypass_state, "state", sizeof(struct ipt_state_info));

  ipt_standard_target_init(&bypass_target, "ACCEPT");

  e = ipt_generate_entry(&bypass_entry, m, (struct ipt_entry_target*)&bypass_target);

  if (iptc_append_entry(chain_name, e, &h) == 0)
  {
    __ERROR_MSG("Error when append:%s\n", iptc_strerror(errno));
    goto out;
  }

  if (iptc_commit(&h) == 0)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }

  out:
  if (e != NULL)  free(e);
  if (m != NULL)  free(m);

  return;
}

static void create_user_defined_chain(const char *chain_name){
  iptc_handle_t h = NULL;
  int result = 0;
  h = iptc_init(FILTER_TABLE);
  if (NULL == h)
  {
    __ERROR_MSG("Error when iptc_init:%s\n", iptc_strerror(errno));
    return;
  }

  if (iptc_is_chain(chain_name, h))
  {
    __ERROR_MSG("%s already exist\n", chain_name);
    goto out;
  }

  result = iptc_create_chain(chain_name, &h);
  if (0 == result)
  {
    __ERROR_MSG("Error when create user-defined chain:%s\n", iptc_strerror(errno));
    goto out;
  }
  result = iptc_commit(&h);
  if (0 == result)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }
  out:
  if (h != NULL)
  {
    iptc_free(&h);
  }
}
static void jump_to_user_defined_chain(const char *main_chain, const char *sub_chain){

  int result = 0;
  struct in_addr param;
  iptc_handle_t h = NULL;
  struct ipt_entry jump_entry;
  struct ipt_standard_target jump_target;
  struct ipt_entry *e = NULL;

  if ((h = iptc_init(FILTER_TABLE)) == NULL)
  {
    return;
  }
  if (0 == iptc_is_chain(sub_chain, h))
  {
    __ERROR_MSG("Chain:%s not exist\n", sub_chain);
    goto out;
  }
  param.s_addr = INADDR_ANY;

  ipt_entry_init(&jump_entry, param, param, param, param, 0, NULL, NULL);

  ipt_standard_target_init(&jump_target, sub_chain);
  e = ipt_generate_entry(&jump_entry, NULL, (struct ipt_entry_target *)&jump_target);
  result = iptc_append_entry(main_chain, e, &h);

  if (0 == result)
  {

    __ERROR_MSG("Error when append:%s\n", iptc_strerror(errno));
    goto out;
  }

  if (iptc_commit(&h) == 0)
  {

    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }

  out:
  if (e != NULL) free(e);
  if (h != NULL)   iptc_free(&h);
}
static void add_queue_rule(const char *chain_name, int protocol){
  iptc_handle_t h = NULL;
  int result = 0;
  struct in_addr param;
  struct ipt_entry queue_entry;
  struct ipt_standard_target queue_target;
  struct ipt_entry *e = NULL;

  h = iptc_init(FILTER_TABLE);
  if (NULL == h)
  {
    __ERROR_MSG("Error when iptc_init:%s\n", iptc_strerror(errno));
    return;
  }
  param.s_addr = INADDR_ANY;
  ipt_entry_init(&queue_entry, param, param, param, param, protocol, NULL, NULL);
  ipt_standard_target_init(&queue_target, "QUEUE");
  e = ipt_generate_entry(&queue_entry, NULL, (struct ipt_entry_target *)&queue_target);
  result = iptc_append_entry(chain_name, e, &h);
  if (0 == result)
  {
    __ERROR_MSG("Error when append:%s\n", iptc_strerror(errno));
    goto out;
  }
  result = iptc_commit(&h);
  if (0 == result)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }
  out:
  if (h != NULL)
  {
    iptc_free(&h);
  }
  if (e != NULL)
  {
    free(e);
  }
}
static void set_default_policy(const char *chain_name, const char *policy){
  iptc_handle_t h = NULL;
  int result = 0;
  h = iptc_init(FILTER_TABLE);
  if (NULL == h)
  {
    __ERROR_MSG("Error when iptc_init:%s\n", iptc_strerror(errno));
    return;
  }
  result = iptc_set_policy(chain_name, policy, NULL, &h);
  if (0 == result)
  {
    __ERROR_MSG("Error when iptc_set_policy:%s\n", iptc_strerror(errno));
    goto out;
  }
  result = iptc_commit(&h);
  if (0 == result)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }
  out:
  if (h != NULL)
  {
    iptc_free(&h);
  }
}

static void ipt_add_user_defined_rules(int proto,
                                       int lpf_value, int lpt_value,
                                       int rpf_value, int rpt_value,
                                       int action, const char *chain_name)
{
  int result = 0;
  struct in_addr param;
  iptc_handle_t h = NULL;;
  struct ipt_entry rule_entry;

  struct ipt_tcp tcp_match;
  struct ipt_udp udp_match;

  struct ipt_entry_match *m = NULL;
  struct ipt_standard_target rule_target;
  struct ipt_entry *e = NULL;

  if ((h = iptc_init(FILTER_TABLE)) == NULL)
  {
    return;
  }
  if (0 == iptc_is_chain(INPUT_USER_DEFINED_CHAIN, h))
  {
    __ERROR_MSG("user-defined chain not exist\n");
    goto out;
  }
  param.s_addr = INADDR_ANY;
  ipt_entry_init(&rule_entry, param, param, param, param, proto, NULL, NULL);
  if (IPPROTO_TCP == proto)
  {
    memset(&tcp_match, 0, sizeof(struct ipt_tcp));
    if (0 == strcmp(chain_name, OUTPUT_USER_DEFINED_CHAIN))
    {
      tcp_match.spts[0] = lpf_value;
      tcp_match.spts[1] = lpt_value;
      tcp_match.dpts[0] = rpf_value;
      tcp_match.dpts[1] = rpt_value;
    }
    else if (0 == strcmp(chain_name, INPUT_USER_DEFINED_CHAIN))
    {
      tcp_match.spts[0] = rpf_value;
      tcp_match.spts[1] = rpt_value;
      tcp_match.dpts[0] = lpf_value;
      tcp_match.dpts[1] = lpt_value;
    }
    m = ipt_generate_match((void *)&tcp_match, "tcp", sizeof(struct ipt_tcp));
  }
  else if (IPPROTO_UDP == proto)
  {
    memset(&udp_match, 0, sizeof(struct ipt_udp));
    if (0 == strcmp(chain_name, OUTPUT_USER_DEFINED_CHAIN))
    {
      udp_match.spts[0] = lpf_value;
      udp_match.spts[1] = lpt_value;
      udp_match.dpts[0] = rpf_value;
      udp_match.dpts[1] = rpt_value;
    }
    else if (0 == strcmp(chain_name, INPUT_USER_DEFINED_CHAIN))
    {
      udp_match.spts[0] = rpf_value;
      udp_match.spts[1] = rpt_value;
      udp_match.dpts[0] = lpf_value;
      udp_match.dpts[1] = lpt_value;
    }
    m = ipt_generate_match((void *)&udp_match, "udp", sizeof(struct ipt_udp));
  }
  ipt_standard_target_init(&rule_target, "ACCEPT");
  e = ipt_generate_entry(&rule_entry, m, (struct ipt_entry_target *)&rule_target);
  result = iptc_append_entry(chain_name, e, &h);

  if (0 == result)
  {

    __ERROR_MSG("Error when append:%s\n", iptc_strerror(errno));
    goto out;
  }

  if (iptc_commit(&h) == 0)
  {

    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }

  out:
  if (e != NULL) free(e);
  if (m != NULL) free(m);
  if (h != NULL) iptc_free(&h);
}

static void ipt_delete_user_defined_rules(int proto,
                                          int lpf_value, int lpt_value,
                                          int rpf_value, int rpt_value,
                                          int action, char *chain_name)
{
  iptc_handle_t h = NULL;
  int rule_num = 0;
  int result = 0;
  h = iptc_init(FILTER_TABLE);
  rule_num = get_user_defined_rule_num(proto,
                                       lpf_value, lpt_value,
                                       rpf_value, rpt_value,
                                       action, chain_name);
  if (-1 == rule_num)
  {
    __ERROR_MSG("Can't find rule_num\n");
    goto out;
  }
  result = iptc_delete_num_entry(chain_name, rule_num, &h);
  if (0 == result)
  {
    __ERROR_MSG("Error when delete:%s\n", iptc_strerror(errno));
    goto out;
  }
  result = iptc_commit(&h);
  if (0 == result)
  {
    __ERROR_MSG("Error when commit:%s\n", iptc_strerror(errno));
    goto out;
  }
  out:
  return;
}
/*-1 means rules not exist*/
static int get_user_defined_rule_num(int proto,
                                     int lpf_value, int lpt_value,
                                     int rpf_value, int rpt_value,
                                     int action, char *chain_name)
{
  int flag = 0;
  int rule_num = 0;
  iptc_handle_t h = NULL;
  const struct ipt_entry *e = NULL;
  int spf = 0, spt = 0, dpf = 0, dpt = 0;
  if (0 == strcmp(chain_name, OUTPUT_USER_DEFINED_CHAIN))
  {
    spf = lpf_value;
    spt = lpt_value;
    dpf = rpf_value;
    dpt = rpt_value;
  }
  else if (0 == strcmp(chain_name, INPUT_USER_DEFINED_CHAIN))
  {
    dpf = lpf_value;
    dpt = lpt_value;
    spf = rpf_value;
    spt = rpt_value;
  }
  h = iptc_init(FILTER_TABLE);
  for (e = iptc_first_rule(chain_name, &h); e != NULL; e = iptc_next_rule(e, &h))
  {
    if (is_find_rule((struct ipt_entry*)e, &h,
                     proto, spf, spt,
                     dpf, dpt, action))
    {
      __RULES_DEBUG("Find user-defined rules\n");
      flag = 1;
      break;
    }
    rule_num ++;
  }
  if (h != NULL)
  {
    iptc_free(&h);
  }
  if (0 == flag)
  {
    rule_num = -1;
  }
  return rule_num;
}
static int is_find_rule(struct ipt_entry *e, iptc_handle_t *h,
                        int proto, int spf, int spt,
                        int dpf, int dpt, int action)
{
  struct ipt_entry_match *m = NULL;
  struct ipt_tcp *m_tcp = NULL;
  struct ipt_udp *m_udp = NULL;
  const char *target_name = NULL;
  int ret = 1;
  m = (struct ipt_entry_match *)e->elems;
  char *caction = NULL;
  caction = (NF_ACCEPT == action ? TEXT_ACTION_ACCEPT : TEXT_ACTION_DROP);

  if (IPPROTO_TCP == proto)
  {
    m_tcp = (struct ipt_tcp *)m->data;
  }
  else if (IPPROTO_UDP == proto)
  {
    m_udp = (struct ipt_udp *)m->data;
  }

  /*protocol*/
  if (proto != e->ip.proto)
  {
    ret = 0;
    goto out;
  }
  /*port*/
  if (IPPROTO_TCP == proto)
  {
    if (m_tcp->spts[0] != spf || m_tcp->spts[1] != spt ||
        m_tcp->dpts[0] != dpf || m_tcp->dpts[1] != dpt)
    {
      ret = 0;
      goto out;
    }
  }
  else if (IPPROTO_UDP == proto)
  {
    if (m_udp->spts[0] != spf || m_udp->spts[1] != spt ||
        m_udp->dpts[0] != dpf || m_udp->dpts[1] != dpt)
    {
      ret = 0;
      goto out;
    }
  }
  /*action*/
  target_name = iptc_get_target(e, h);
  if (strcmp(target_name, caction) != 0)
  {
    ret = 0;
    goto out;
  }
  out:
  return ret;
}
static void *fw_malloc(size_t size)
{
  void *p;

  if ((p = malloc(size)) == NULL)
  {
    __ERROR_MSG("Error when malloc\n");
    exit(1);
  }

  memset(p, 0, size);
  return p;
}

static struct ipt_entry_match *ipt_generate_match(void *extend_match,
                                                  const char *extend_match_name,
                                                  int extend_match_size)
{
  struct ipt_entry_match *m = NULL;
  int size = 0;

  size = IPT_ALIGN(sizeof(struct ipt_entry_match) + extend_match_size);

  m = fw_malloc(size);
  memset(m, 0, size);
  m->u.match_size = size;

  strncpy(m->u.user.name, extend_match_name, 25);
  memcpy( m->data, extend_match, extend_match_size);

  return m;
}

static struct ipt_entry *ipt_generate_entry(struct ipt_entry *fw,
                                            struct ipt_entry_match *match,
                                            struct ipt_entry_target *target)
{
  unsigned int size1 = 0;
  unsigned int size2 = 0;
  unsigned int size3 = 0;
  struct ipt_entry *e = NULL;
  size1 = IPT_ALIGN(sizeof(struct ipt_entry));
  if (match != NULL)
  {
    size2 = match->u.match_size;
  }
  size3 = target->u.target_size;

  e = fw_malloc(size1 + size2 + size3);
  memset(e, 0, size1 + size2 + size3);

  *e = *fw;
  e->target_offset = size1 + size2;
  e->next_offset = size1 + size2 + size3;

  if (match != NULL)
  {
    memcpy(e->elems, match, size2);
  }

  memcpy(e->elems + size2, target, size3);
  return e;
}

static void ipt_entry_init(struct ipt_entry* entry, struct in_addr s_ip, struct in_addr s_mask,
                           struct in_addr d_ip, struct in_addr d_mask, unsigned short proto,
                           const char *in_iface, const char *out_iface){
  memset(entry, 0, sizeof(struct ipt_entry)); /* zero it out */

  entry->ip.src = s_ip;   /* src address */
  entry->ip.smsk = s_mask;  /* mask */
  entry->ip.dst = d_ip;   /* dst address */
  entry->ip.dmsk = d_mask;  /* mask */
  entry->ip.proto = proto;

  if (in_iface != NULL)
  {
    strncpy(entry->ip.iniface, in_iface, IF_NAMSIZ);
  }
  if (out_iface != NULL)
  {

    strncpy(entry->ip.outiface, out_iface, IF_NAMSIZ);
  }
}

static void ipt_standard_target_init(struct ipt_standard_target *target, const char *policy)
{
  memset(target, 0, sizeof(struct ipt_standard_target));
  target->target.u.target_size = sizeof(struct ipt_standard_target);
  strncpy(target->target.u.user.name, policy, 30);
}
static struct ipt_entry_target* ipt_generate_target(void *extend_target,
                                                    int extend_target_size,
                                                    const char *target_name)
{
  struct ipt_entry_target *t = NULL;
  int size = 0;
  size = IPT_ALIGN(sizeof(struct ipt_entry_target) + extend_target_size);
  t = fw_malloc(size);
  t->u.target_size = size;
  memcpy(t->data, extend_target, extend_target_size);
  strncpy(t->u.user.name, target_name, 30);

  return t;
}

